#include "dicomdir.h"
#include "gdcmReader.h"
#include "gdcmStreamImageReader.h"
#include <gdcmStringFilter.h>
#include <gdcmAttribute.h>

std::string str( const gdcm::Value & val ) {
  std::stringstream strm;
  strm << val;
  return strm.str();
}

std::string str( gdcm::SmartPointer<gdcm::Value> val ) {
  std::stringstream strm;
  strm << *val;
  return strm.str();
}

QString qStr( const gdcm::Value & val ) {
  std::stringstream strm;
  strm << val;
  return QString::fromStdString(strm.str());
}

QString qStr( gdcm::SmartPointer<gdcm::Value> val ) {
  std::stringstream strm;
  strm << *val;
  return QString::fromStdString(strm.str());
}

QTreeWidgetItem *DicomDir::getTreeItem() const {
  QStringList data = {title, filename};
  QTreeWidgetItem *item = new QTreeWidgetItem(data);
  foreach (Patient p, patient) {
    item->addChild(p.getTreeItem());
  }
  return item;
}

DicomDir::DicomDir() {

}

bool DicomDir::open(const QString & filename) {
  QFileInfo fileInfo(filename);
  if(!fileInfo.isFile()) {
    std::cerr << "Its not a file!" << std::endl;
    return false;
  }

  this->title = fileInfo.baseName();
  this->filename = filename;

  QDir dir = fileInfo.absoluteDir();
  gdcm::Reader reader;
//  std::cout << "Opening " << filename.toStdString() << std::endl;
  reader.SetFileName(filename.toUtf8());
  if( !reader.Read() ) {
    std::cerr << "Cannot read file!" << std::endl;
    return false;
  }
  const gdcm::File &file = reader.GetFile();
  const gdcm::FileMetaInformation header =  file.GetHeader();
//  std::cout << header << std::endl;

  const gdcm::DataSet &ds = file.GetDataSet();
  gdcm::MediaStorage ms;
  ms.SetFromFile(file);
  if(gdcm::MediaStorage::GetMSType( ms.GetString() ) !=gdcm::MediaStorage::MediaStorageDirectoryStorage) {
    std::cerr << "This file is not a DICOMDIR (Media storage type: " << ms << " );\n";
    return false;
  }
  if( header.FindDataElement(gdcm::Tag(0x0002, 0x0002))) {
    if( str( header.GetDataElement(gdcm::Tag(0x0002, 0x0002) ).GetValue()) != "1.2.840.10008.1.3.10" ) {
      std::cerr << "This file is not a DICOMDIR" << std::endl;
    }
  } else {
    std::cerr << "Media Storage SOP Class not present" << std::endl;
    return false;
  }

  for( auto it = ds.GetDES().begin(); it != ds.GetDES().end(); ++it ) {
    const gdcm::DataElement &de = *it;
    if( de.GetTag() ==gdcm::Tag(0x004, 0x1220) ) {
      gdcm::SmartPointer<gdcm::SequenceOfItems>sq = de.GetValueAsSQ();
      for( size_t itemNr = 1; itemNr < sq->GetNumberOfItems(); ++ itemNr ) {
        gdcm::Item &item = sq->GetItem(itemNr);
        if( item.FindDataElement(gdcm::Tag(0x0004, 0x1430))) {
          gdcm::SmartPointer<gdcm::Value> val = item.GetDataElement(gdcm::Tag(0x0004, 0x1430)).GetValue();
          while( str(val) == "PATIENT " || str(val) == "PATIENT") {
            Patient p;
//            std::cout << str(val) << std::endl;
            if(item.FindDataElement(gdcm::Tag(0x0010, 0x0010))) {
              val = item.GetDataElement(gdcm::Tag(0x0010, 0x0010)).GetValue();
//              std::cout << "Name = " << *val << std::endl;
              p.setName(qStr(val));
            }
            if(item.FindDataElement(gdcm::Tag(0x0010, 0x0020))) {
              val = item.GetDataElement(gdcm::Tag(0x0010, 0x0020)).GetValue();
//              std::cout << "ID = " << *val << std::endl;
              p.setId(qStr(val));
            }
            //Next
            item = sq->GetItem(++itemNr);
            if( item.FindDataElement(gdcm::Tag(0x0004, 0x1430))) {
              val = item.GetDataElement(gdcm::Tag(0x0004, 0x1430)).GetValue();
            }

            while( str(val) == "STUDY " || str(val) == "STUDY") {
              Study study;
//              std::cout << str(val) << std::endl;
              if( item.FindDataElement(gdcm::Tag(0x0020, 0x000d))) {
                val = item.GetDataElement(gdcm::Tag(0x0020, 0x000d)).GetValue();
//                std::cout << "  UID = " << *val << std::endl;
                study.setUid(qStr(val));
              }
              if( item.FindDataElement(gdcm::Tag(0x0008, 0x0020))) {
                val = item.GetDataElement(gdcm::Tag(0x0008, 0x0020)).GetValue();
//                std::cout << "  Date = " << *val << std::endl;
                study.setDate(qStr(val));
              }
              if( item.FindDataElement(gdcm::Tag(0x0008, 0x1030))) {
                val = item.GetDataElement(gdcm::Tag(0x0008, 0x1030)).GetValue();
//                std::cout << "  Description = " << *val << std::endl;
                study.setDescr(qStr(val));
              }
              item = sq->GetItem(++itemNr);
              if( item.FindDataElement(gdcm::Tag(0x0004, 0x1430))) {
                val = item.GetDataElement(gdcm::Tag(0x0004, 0x1430)).GetValue();
              }
              while( str(val) == "SERIES " || str(val) == "SERIES") {
                Series series;
//                std::cout << "  " << str(val) << std::endl;
                if( item.FindDataElement(gdcm::Tag(0x0020, 0x000e))) {
                  val = item.GetDataElement(gdcm::Tag(0x0020, 0x000e)).GetValue();
//                  std::cout << "    UID = " << *val << std::endl;
                  series.setUid(qStr(val));
                }
                if( item.FindDataElement(gdcm::Tag(0x0008, 0x0060))) {
                  val = item.GetDataElement(gdcm::Tag(0x0008, 0x0060)).GetValue();
//                  std::cout << "    Modality = " << *val << std::endl;
                  series.setModality(qStr(val));
                }
                if( item.FindDataElement(gdcm::Tag(0x0008, 0x103e))) {
                  val = item.GetDataElement(gdcm::Tag(0x0008, 0x103e)).GetValue();
//                  std::cout << "    Description = " << *val << std::endl;
                  series.setDescr(qStr(val));
                }
                item = sq->GetItem(++itemNr);
                if( item.FindDataElement(gdcm::Tag(0x0004, 0x1430))) {
                  val = item.GetDataElement(gdcm::Tag(0x0004, 0x1430)).GetValue();
                }
                while( str(val) == "IMAGE " || str(val) == "IMAGE") {
                  ImageInfo imageInfo;
                  imageInfo.setDir(dir);
//                  std::cout << "    " << item << std::endl;
//                  std::cout << "    " << *val << std::endl;
                  if( item.FindDataElement(gdcm::Tag(0x0004, 0x1511))) {
                    val = item.GetDataElement(gdcm::Tag(0x0004, 0x1511)).GetValue();
//                    std::cout << "      UID = " << *val << std::endl;
                    imageInfo.setUid(qStr(val));
                  }
                  if( item.FindDataElement(gdcm::Tag(0x0004, 0x1500))) {
                    val = item.GetDataElement(gdcm::Tag(0x0004, 0x1500)).GetValue();
//                    std::cout << "      ReferencedFileID = " << *val << std::endl;
                    imageInfo.setReferencedFileID(qStr(val));

                  }
                  if(itemNr < sq->GetNumberOfItems()) {
                    item = sq->GetItem(++itemNr);
                    if( item.FindDataElement(gdcm::Tag(0x0004, 0x1430))) {
                      val = item.GetDataElement(gdcm::Tag(0x0004, 0x1430)).GetValue();
                    }
                  } else {
                    break;
                  }
                  series.addImage(imageInfo);
                }
                study.addSeries(series);
              }
              p.addStudy(study);
            }
            patient.push_back(p);
          }
        }
      }
    }
  }
  return true;
}
